/**
 * Copyright 2009 University of  Washington
 * This code is released under the GPL version 3 - with a copy of the license included
 * @author Maya Hao Li
 *
 */package seedpod.model;

import java.util.HashMap;

import seedpod.kb2db.ClsMap;
import seedpod.kb2db.ModelMap;


public class SeedpodObjectFactory {

	public static final int UNKNOWN_OID = 0;	
	public static final String FACTORY_PACKAGE = "edu.washington.biostr.sig.seedpod.model.plugin";
	public static final Class<SeedpodDO> DEFAULT_SEEDPOD_DATA_OBJECT_CLASS = SeedpodDO.class;

	private static HashMap<String, Class<?>> _objectClsRegister = new HashMap<String, Class<?>>();
	
	private static SeedpodObjectFactory _instance = new SeedpodObjectFactory();

	private SeedpodObjectFactory() {}

	public static SeedpodObjectFactory getInstance() {
		if ( _instance == null )
			return new SeedpodObjectFactory();
		else
			return _instance;
	}

	public void register( String classType, Class<?> classRef ) {
		_objectClsRegister.put( classType, classRef );
	}

	private Class<?> getRegisteredJavaClass( String clsName ) {
		return _objectClsRegister.get( clsName );
	}

	public Class<?> getImplJavaClass( String clsName ) {
		ClsMap metaCls = null, metaSuperCls = null;
		String metaClsName = null;
		Class<?> objClass = DEFAULT_SEEDPOD_DATA_OBJECT_CLASS;

		// find the self implemented class first
		objClass = getRegisteredJavaClass( clsName );
		if ( objClass != null )
			return objClass;

		// find the meta class (not superclass)
		metaCls = getMetaCls( clsName );
		if ( metaCls != null ) {
			metaClsName = metaCls.getName();
			objClass = getRegisteredJavaClass( metaClsName );
			if ( objClass != null )
				return objClass;
		} else
			return DEFAULT_SEEDPOD_DATA_OBJECT_CLASS;

		// if no metaCls is found in the previous step
		// traverse up the metaclass tree until reaching RDB_CLS
		do {
			metaSuperCls = getParentCls( metaCls ); // getSuperCls( metaClsName );

			if ( metaSuperCls != null ) {
				metaClsName = metaSuperCls.getName();

				if ( metaClsName.equalsIgnoreCase( SeedpodModel.DEFAULT_META_RDB_CLASS ) )
					objClass = DEFAULT_SEEDPOD_DATA_OBJECT_CLASS;
				else
					objClass = getRegisteredJavaClass( metaClsName );
			} else
				break;

		}
		while (objClass == null);

		return objClass;
	}

	private ClsMap getMetaCls( String clsName ) {
		ClsMap metaCls = null;
		ModelMap map = ModelMap.getInstance();
		String metaClsName = null;
		ClsMap cMap = map.getClsMap( clsName );

		if ( cMap != null ) {
			metaClsName = cMap.getClsType();
			// metaClsName = cMap.getParentClsName();
			metaCls = map.getClsMap( metaClsName );
		}

		return metaCls;
	}

	private ClsMap getParentCls( ClsMap metaCls ) {
		String parentClsName = metaCls.getParentClsName();
		return ModelMap.getInstance().getClsMap( parentClsName );
	}

	public SeedpodDO getObject( int i, String toCls ) {
		// TODO Auto-generated method stub
		return null;
	}

	/**
	 * find the super class of a given class name
	 * 
	 * @param clsName
	 * @return
	 */
	// private Cls getSuperCls( String clsName ) {
	// Cls superCls = null;
	// KnowledgeBase kb = Seedpod.getKnowledgeBase();
	// Cls cls = kb.getCls( clsName );
	// if ( cls == null )
	// return superCls;
	//
	// // each class can have multiple classes. it's up to the modeler to distinguish
	// // the ambiguity. the engine will only find the first available implemented class
	// Collection superClsCollection = kb.getSuperclasses( cls );
	// if ( !superClsCollection.isEmpty() ) {
	// Iterator scIter = superClsCollection.iterator();
	// while (scIter.hasNext()) {
	// superCls = (Cls)scIter.next();
	// getRegisteredJavaClass( superCls.getName() );
	// }
	// }
	// return superCls;
	// }
}
